package user

import (
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"go.mongodb.org/mongo-driver/bson"
	"higame/config"
	"higame/model/integral"
	"higame/modules/crypto"
	"higame/modules/log"
	"higame/modules/role"
	"higame/modules/statuscode"
	"higame/modules/store"
	"higame/modules/utils"
	log2 "higame/routes/log"
	"net/http"
)

// 用户登录
func login(ctx *gin.Context) {
	u, err := validatorForLogin(ctx)

	// 验证客户端数据不通过
	if err != nil {
		ctx.JSON(statuscode.VERIFICATION_FAILED, gin.H{
			"code": statuscode.VERIFICATION_FAILED,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	now := utils.Timestamp()
	// 登录成功,更新登录信息
	err = UpdateOneByName(u.Username, bson.M{
		"last_login_time": now,
		"last_check_time": now,
		"pc_code":         u.PcCode,
		"client_id":       u.ClientID,
	})

	if err != nil {
		log.Error.Println("更新登录信息失败：", err)
	}

	// 添加登录日志
	err = log2.AddOneLoginLog(&log2.LoginLogSchema{
		AddTime:       now,
		Username:      u.Username,
		LastLoginTime: now,
		LastCheckTime: now,
		IP:            ctx.ClientIP(),
		Success:       true,
		Location:      utils.IP2Region(ctx.ClientIP()),
		Text:          "登录成功",
		PcCode:        u.PcCode,
		ClientID:      u.ClientID,
	})

	if err != nil {
		log.Error.Println("添加登录日志错误：", err)
	}

	// 登录成功生成jwt token
	token, err := generateToken(u.Username, u.UUID, u.Role)
	if err != nil {
		log.Error.Println("生成jwt token失败：", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code": http.StatusInternalServerError,
			"msg":  "登录失败，服务器生成token失败",
			"data": nil,
		})
		return
	}

	u.Password = "" //清空敏感数据，然后返回客户端
	ctx.JSON(http.StatusOK, gin.H{
		"code":  http.StatusOK,
		"msg":   "登录成功！",
		"data":  u,
		"token": token,
	})

}

// 重置密码
func resetPassword(ctx *gin.Context) {
	claims, _ := store.GetClaims(ctx)
	newpwd := ctx.PostForm("newpwd")
	oldpwd := ctx.PostForm("oldpwd")
	if len(newpwd) < 5 {
		ctx.JSON(http.StatusNotAcceptable, gin.H{
			"code": http.StatusNotAcceptable,
			"msg":  "新密码不能少于5位！",
			"data": nil,
		})
		return
	}
	u, err := FindOneByName(claims.Audience)
	if err != nil {
		ctx.JSON(http.StatusNotAcceptable, gin.H{
			"code": http.StatusNotAcceptable,
			"msg":  "当前登录的用户名没有查找到！",
			"data": nil,
		})
		return
	}

	// 密码错误
	if u.Password != crypto.Md5encrypt(oldpwd) {
		ctx.JSON(http.StatusUnauthorized, gin.H{
			"code": http.StatusUnauthorized,
			"msg":  "旧密码错误！",
			"data": nil,
		})
		return
	}

	// 修改密码
	err = UpdateOneByName(claims.Audience, bson.M{
		"password": crypto.Md5encrypt(newpwd),
	})

	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code": http.StatusInternalServerError,
			"msg":  err,
			"data": nil,
		})
		return
	}

	//修改成功
	ctx.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "修改成功！",
		"data": nil,
	})
}

// 查找密码
func findPassword(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "暂时无法查询，请联系管理员修改！",
		"data": nil,
	})
}

// 添加收货地址
func addAddress(ctx *gin.Context) {
	claims, err := store.GetClaims(ctx)
	if err != nil {
		// 获取当前登录的用户失败
		log.Error.Println(err)
		ctx.JSON(500, gin.H{
			"code": 500,
			"msg":  "内部服务器出错！",
			"data": nil,
		})
		return
	}

	v, err := validatorForAddress(ctx)
	if err != nil {
		// 获取当前登录的用户失败
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	if addressList, err := GetAddressByName(claims.Audience); err != nil {
		// 错误地址没有找到
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	} else if len(addressList) >= 5 {
		// 最多只能添加5个地址
		ctx.JSON(400, gin.H{
			"code": 204,
			"msg":  "最多只能添加5个地址",
			"data": nil,
		})
		return
	}
	if err := UpdateOne(bson.M{
		"username": claims.Audience,
	}, bson.M{
		"$push": bson.M{
			"address": &AddressSchema{
				UUID:     uuid.NewV1().String(),
				Address:  v.Address,
				Tel:      v.Tel,
				Name:     v.Name,
				PostCode: v.PostCode,
			},
		},
	}); err !=nil {
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  "添加用户地址失败",
			"data": nil,
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "添加地址成功",
		"data": nil,
	})
}

// 删除收货地址
func delAddress(ctx *gin.Context) {
	claims, err := store.GetClaims(ctx)
	if err != nil {
		// 获取当前登录的用户失败
		log.Error.Println(err)
		ctx.JSON(500, gin.H{
			"code": 500,
			"msg":  "内部服务器出错！",
			"data": nil,
		})
		return
	}
	uuid := ctx.PostForm("uuid")
	username := claims.Audience

	if err := UpdateOne(bson.M{
		"username": username,
	}, bson.M{
		"$pull": bson.M{
			"address": bson.M{
				"uuid": uuid,
			},
		},
	}); err !=nil {
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  "删除失败",
			"data": nil,
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "删除地址成功",
		"data": nil,
	})
}

// 修改收货地址
func updateAddress(ctx *gin.Context) {
	claims, err := store.GetClaims(ctx)
	if err != nil {
		// 获取当前登录的用户失败
		log.Error.Println(err)
		ctx.JSON(500, gin.H{
			"code": 500,
			"msg":  "内部服务器出错！",
			"data": nil,
		})
		return
	}

	v, err := validatorForAddress(ctx)
	if err != nil {
		// 获取当前登录400失败
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	if err := UpdateOne(bson.M{
		"username":     claims.Audience,
		"address.uuid": v.UUID,
	}, bson.M{
		"$set": bson.M{
			"address.$.address":   v.Address,
			"address.$.tel":       v.Tel,
			"address.$.name":      v.Name,
			"address.$.post_code": v.PostCode,
		},
	}); err !=nil {
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "修改地址成功",
		"data": nil,
	})
}

// 获取收货地址
func getAddress(ctx *gin.Context) {
	claims, err := store.GetClaims(ctx)
	if err != nil {
		// 获取当前登录的用户失败
		log.Error.Println(err)
		ctx.JSON(500, gin.H{
			"code": 500,
			"msg":  "内部服务器出错！",
			"data": nil,
		})
		return
	}
	username := ctx.PostForm("username")
	if claims.Audience != config.AdminName {
		username = claims.Audience
	}

	if u, err:=FindOneByName(username); err != nil {
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	} else {
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "获取地址成功",
			"data": u.Address,
		})
	}
}

// 用户验证
func check(ctx *gin.Context) {
	u, err := validatorForCheck(ctx)
	if err != nil {
		ctx.JSON(statuscode.VERIFICATION_FAILED, gin.H{
			"code": statuscode.VERIFICATION_FAILED,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	err = UpdateOneByName(u.Username, bson.M{
		"last_check_time": utils.Timestamp(),
	})

	if err != nil {
		log.Error.Println(err)
	}

	// 登录成功生成jwt token
	token, err := generateToken(u.Username, u.UUID, u.Role)

	u.Password = ""
	ctx.JSON(http.StatusOK, gin.H{
		"code":  http.StatusOK,
		"msg":   "验证成功",
		"data":  u,
		"token": token,
	})
}

// 用户添加-管理员权限
func create(ctx *gin.Context) {
	u, err := validatorForCreate(ctx)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}
	shareCode := ctx.PostForm("share_code")
	// 查询邀请码
	if _, err := FindOne(bson.M{
		"share_code": shareCode,
	}); err != nil {
		ctx.JSON(400, gin.H{
			"code": 400,
			"msg":  "邀请码不存在",
			"data": nil,
		})
		return
	}

	// 邀请日志;在一台电脑上连续注册超三个以上进行检测是否是恶意注册的
	// 恶意注册需要等十分钟
	if shareLogs := log2.FindManyShareLog(0, bson.M{
		"ip":         ctx.ClientIP(),
	}); len(shareLogs) >= 3 {
		if utils.Timestamp()-shareLogs[0].AddTime < 1000*60*10 {
			ctx.JSON(400, gin.H{
				"code": 400,
				"msg":  "服务器繁忙，请过段时间再试！",
				"data": nil,
			})
			return
		}
	}

	//添加用户
	if err := AddOne(u); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code": http.StatusInternalServerError,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	// 发放积分
	task, err := integral.FindOneByTaskName("SHARE")
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code": http.StatusInternalServerError,
			"msg":  "服务器内部出错",
			"data": nil,
		})
		return
	}

	if err := UpdateOne(bson.M{
		"share_code": shareCode,
	}, bson.M{
		"$inc": bson.M{
			"integral": task.Integral,
		},
	}); err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"code": http.StatusInternalServerError,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	// 添加积分日志
	master, _ := FindOne(bson.M{"share_code": shareCode})
	_ = log2.AddOneIntegralLog(&log2.IntegralLogSchema{
		UUID:     uuid.NewV1().String(),
		AddTime:  utils.Timestamp(),
		Username: master.Username,
		Integral: task.Integral,
		Text:     task.Title,
		Other:    "成功邀请一位用户：" + u.Username,
	})

	// 添加分享日志
	_ = log2.AddOneShareLog(&log2.ShareLogSchema{
		UUID:       uuid.NewV1().String(),
		AddTime:    utils.Timestamp(),
		Master:     master.Username,
		ShareCode:  master.ShareCode,
		Apprentice: u.Username,
		IP:         ctx.ClientIP(),
		Remark:     "",
	})
	ctx.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "添加用户成功！",
		"data": nil,
	})
}

// 删除用户-管理员权限
func delete(ctx *gin.Context) {
	u, err := validatorForDelete(ctx)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	err = DeleteOneByName(u.Username)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  "删除用户失败！",
			"data": nil,
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "删除用户成功！",
		"data": nil,
	})
}

// 更新用户-管理员权限
func update(ctx *gin.Context) {
	action := ctx.Query("action")
	u, err := validatorForUpdate(ctx)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	if action == "lock" {
		err = UpdateOneByName(u.Username, bson.M{
			"is_lock": u.IsLock,
		})

		if err == nil {
			ctx.JSON(http.StatusOK, gin.H{
				"code": http.StatusOK,
				"msg":  "更新用户成功！",
				"data": nil,
			})
		} else {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"code": http.StatusBadRequest,
				"msg":  "没有修改任何数据！",
				"data": nil,
			})
		}
		return
	}

	if action == "change" {
		update := bson.M{
			"nick":     u.Nick,
			"integral": u.Integral,
			"email":    u.Email,
			"qq":       u.QQ,
			"wx":       u.WX,
			"tel":      u.Tel,
			"bd_info":  u.BdInfo,
		}

		if u.Password != "" {
			update["password"] = crypto.Md5encrypt(u.Password)
		}

		err = UpdateOneByName(u.Username, update)
		if err != nil {
			ctx.JSON(http.StatusBadRequest, gin.H{
				"code": http.StatusBadRequest,
				"msg":  "没有修改任何数据！",
				"data": nil,
			})
			return
		}

		ctx.JSON(http.StatusOK, gin.H{
			"code": http.StatusOK,
			"msg":  "更新用户成功！",
			"data": nil,
		})
		return
	}
	ctx.JSON(http.StatusBadRequest, gin.H{
		"code": http.StatusBadRequest,
		"msg":  "参数错误！",
		"data": nil,
	})
}

// 获取一个用户信息-管理员权限
func get(ctx *gin.Context) {
	username := ctx.PostForm("username")

	u, err := FindOneByName(username)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": http.StatusBadRequest,
			"msg":  err.Error(),
			"data": nil,
		})
		return
	}

	u.Password = ""
	ctx.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "查询成功！",
		"data": u,
	})
}

// 获取多个用户信息-管理员权限
func list(ctx *gin.Context) {
	where := bson.M{}
	filterType := ctx.PostForm("filterType")
	filterText := ctx.PostForm("filterText")
	switch filterType {
	case "locked":
		// 查看锁定用户
		where["is_lock"] = true
		break
	case "online":
		// 查看在线用户
		where["last_check_time"] = bson.M{
			"$gt": utils.Timestamp() - config.Set.CheckTime,
		}
		break
	default:
		if filterType != "-1" {
			where[filterType] = bson.M{
				"$regex":   filterText,
				"$options": "$i",
			}
		}
	}

	// 只允许查询用户
	where["role"] = role.USER
	pageNum := utils.StringToInt64(ctx.PostForm("pageNum"), 1) - 1
	users, _ := FindAll(pageNum, where)
	count, _ := Count(where)
	var list = make([]bson.M, 0)
	now := utils.Timestamp()
	for _, item := range users {
		u, _ := Parse(item)
		// 验证是否在线
		if (now - u.LastCheckTime) < config.Set.CheckTime {
			item["online"] = true
		} else {
			item["online"] = false
		}
		item["password"] = ""
		list = append(list, item)
	}
	str := ""
	if count == 0 {
		str = "没有查询到数据！"
	} else {
		str = utils.JoinString("共%v页%v行 当前在第%v页", count/20+1, count, pageNum+1)
	}
	ctx.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  str,
		"data": gin.H{
			"list":  list,
			"total": count,
		},
	})
}
